﻿using Commons;
using IRMSService;
using JWT;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Redis;
using RMSModel;
using RMSModel.Common;
using RMSModel.Models;
using RMSModel.VMModels;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace RMSServiceImpl
{
    public class LoginServiceImpl : ILoginService
    {
        private readonly RMSDB db;
        private readonly ITokenHelper tokenHelper;
        private readonly IRedisService redisService;
        private readonly ILogger<LoginServiceImpl> _logger;
        public LoginServiceImpl(RMSDB db, ITokenHelper tokenHelper, IRedisService redisService, ILogger<LoginServiceImpl> logger)
        {
            this.db = db;
            this.tokenHelper = tokenHelper;
            this.redisService = redisService;
            this._logger = logger;
        }
        public ResultType ResetUserPassword(int id )
        {
            ResultType result = new ResultType();
            try
            {
                user u = db.users.Find(id);
                u.Password= MD5Utils.GetMD5_32(MD5Utils.GetMD5_32("123456"));
                db.users.Update(u);
                db.SaveChanges();
            }
            catch(Exception ex)
            {
                result.ResultCode = 1;
                result.ResultMsg = ex.Message;
            }
            return result;
        }
        public ResultType<string> login(string account, string password,string guid ,string code)
        {
            ResultType<string> result = new ResultType<string>();
            try
            {
                if (!redisService.ExistsByKeyAsync(guid).Result)
                {
                    result.ResultCode = 1;
                    result.ResultMsg = "验证码过期！";
                    return result;
                }
                string ocode = redisService.FindByKeyAsync<string>(guid).Result;
                if (!code.Equals(ocode))
                {
                    result.ResultCode = 1;
                    result.ResultMsg = "验证码错误！";
                    return result;
                }
                user u = db.users.FirstOrDefault(p => p.LoginName == account);
                password = MD5Utils.GetMD5_32(password);
                if (null != u)
                {
                    if (!u.Password.Equals(password))
                    {
                        result.ResultCode = 1;
                        result.ResultMsg = "密码错误！";
                        return result;
                    }
                    Dictionary<string, string> keyValuePairs = new Dictionary<string, string>
                    {
                        { "userId", account }
                    };
                    string token = tokenHelper.CreateToken(keyValuePairs).TokenStr;
                    result.Data = token; 
                    ///获取该用户的接口权限

                    if (redisService != null)
                        redisService.AddOrUpdateByKeyAsync(account, token, DateTime.Now.AddSeconds(600));
                }
                else
                {
                    result.ResultCode = 1;
                    result.ResultMsg = "用户不存在！";
                }
            }
            catch(Exception ex)
            {
                result.ResultCode = 1;
                result.ResultMsg = ex.Message;
                _logger.LogError(ex.Message);
            }
            
            return result;
        }

        //public MemoryStream GetVerifyCode(string id)
        //{
        //    
        //}
        #region 菜单

        private List<menu> GetMenusByUser(int userid)
        {
            string sql = @"select m.* from menu m
                                        LEFT JOIN rolemenu rm on m.id = rm.MenuId
                                        LEFT JOIN role r on r.Id = rm.RoleId
                                        LEFT JOIN userrole ur on r.Id = ur.RoleId
                                        where ur.UserId = {0}";
            sql = string.Format(sql, userid);
            return db.menus.FromSqlRaw(sql).ToList();
        }
        public ResultType<Dictionary<string,object>> GetAllMenuByUser(string userId)
        {
            ResultType<Dictionary<string, object>> result = new ResultType<Dictionary<string, object>>();
            InitModel rms = new InitModel();
            
            try
            {

                rms.homeInfo = db.home.ToList().First();
                rms.logoInfo = db.logo.ToList().First();
                user u = db.users.FromSqlRaw(string.Format( "select * from user where loginName='{0}'", userId)).FirstOrDefault();
                var mdata = GetMenusByUser(u.Id);
                List<VMMenu> menuModels = new List<VMMenu>();
                foreach (menu m in mdata)
                {
                    if(m.MType == 0 || m.MType == 1 || m.MType == 2)
                    {
                        VMMenu menu = new VMMenu() { href = m.href, title = m.title, icon = m.icon, id = m.id, parentid = m.parentid };
                        menuModels.Add(menu);
                    }
                }

                Dictionary<int, VMMenu> dict = menuModels.ToDictionary(loc => loc.id);

                foreach (VMMenu loc in dict.Values)
                {
                    if (loc.parentid == 0)
                    {
                        continue;
                    }

                    if (loc.parentid != loc.id)
                    {
                        dict[loc.parentid].child.Add(loc);
                    }
                }
                foreach (VMMenu loc in dict.Values)
                {
                    if (loc.parentid != 0)
                    {
                        dict.Remove(loc.id);
                    }
                }
                rms.menuInfo = dict.Values.ToList();
                var data = GetMenusByUser(u.Id).Select(p => p.authcode).ToList();
                redisService.AddOrUpdateByKeyAsync(userId + "_role", data);
                VMUser user = new VMUser() { rolemenus = data,UserName=u.UserName};
                result.Data.Add("rms",rms);
                result.Data.Add("user", user);
            }
            catch (Exception ex)
            {
                result.ResultCode = 1;
                result.ResultMsg = ex.Message;
                _logger.LogError(ex.Message);
            }
            return result;
        }

        public ResultType<List<VMMenu>> GetAllMenu()
        {
            ResultType<List<VMMenu>> result = new ResultType<List<VMMenu>>();
            try
            {
                var data = from m1 in db.menus
                           join m2 in db.menus on m1.parentid equals m2.id into m2_join
                           from m2 in m2_join.DefaultIfEmpty()
                           select new VMMenu
                           {
                               id = m1.id,
                               parentid = m1.parentid,
                               title = m1.title,
                               parentname = m2.title,
                               href = m1.href,
                               MType = m1.MType,
                               status = m1.status,
                               createtime = m1.createtime,
                               createuser=m1.createuser,
                               updatetime=m1.updatetime,
                               updateuser=m1.updateuser,
                               authcode=m1.authcode
                              
                           };
                result.Data = data.ToList();
            }
            catch(Exception ex)
            {
                result.ResultCode = 1;
                result.ResultMsg = ex.Message;
                _logger.LogError(ex.Message);
            }
            return result;
        }
        public List<TreeModel> GetAllMenuTree()
        {
            List<VMMenu> data = GetAllMenu().Data;
            List<TreeModel> treeModels = new List<TreeModel>();
            foreach (VMMenu m in data)
            {
                TreeModel menu = new TreeModel() { id = m.id.ToString(), parentid = m.parentid.ToString(), code = m.id.ToString(), name = m.title,parentname=m.parentname,open=m.open };
                treeModels.Add(menu);
            }
            Dictionary<string, TreeModel> dict = treeModels.ToDictionary(loc => loc.id);

            foreach (TreeModel loc in dict.Values)
            {
                if ("0".Equals(loc.parentid))
                {
                    continue;
                }

                if (loc.parentid != loc.id)
                {
                    dict[loc.parentid].children.Add(loc);
                }
            }
            foreach (TreeModel loc in dict.Values)
            {
                if (!"0".Equals(loc.parentid))
                {
                    dict.Remove(loc.id);
                }
            }

            return dict.Values.ToList();
        }

        public ResultType<menu> GetMenuById(int id)
        {
            ResultType<menu> result = new ResultType<menu>();
            try
            {
                result.Data = db.menus.Find(id);
            }
            catch (Exception ex)
            {
                result.ResultCode = 1;
                result.ResultMsg = ex.Message;
            }
            return result;
        }

        public ResultType AddMenu(menu m)
        {
            ResultType result = new ResultType();
            try
            {
                db.menus.Add(m);
                db.Entry(m).Property(p => p.createtime).IsModified = false;
                db.Entry(m).Property(p => p.createuser).IsModified = false;
                db.SaveChanges();
            }
            catch (Exception ex)
            {
                result.ResultCode = 1;
                result.ResultMsg = ex.Message;
                _logger.LogError(ex.Message);
            }
            return result;
        }

        public ResultType UpdateMenu(menu m)
        {
            ResultType result = new ResultType();
            try
            {
                db.menus.Update(m);
                db.SaveChanges();
            }
            catch (Exception ex)
            {
                result.ResultCode = 1;
                result.ResultMsg = ex.Message;
                _logger.LogError(ex.Message);
            }
            return result;
        }

        public ResultType DeleteMenu(List<menu> m)
        {
            ResultType result = new ResultType();
            try
            {
                db.menus.RemoveRange(m);
                db.SaveChanges();
            }
            catch (Exception ex)
            {
                result.ResultCode = 1;
                result.ResultMsg = ex.Message;
                _logger.LogError(ex.Message);
            }
            return result;
        }
        #endregion

        #region 用户
        public ResultType<List<VMUser>> GetAllUser()
        {
            ResultType<List<VMUser>> result = new ResultType<List<VMUser>>();
            List<VMUser> list = new List<VMUser>();
            try
            {
                var data = db.roles;
                var roles = data.ToList().ToDictionary(p=>p.Id);
                var user = db.users;
                foreach (var u in user)
                {
                    VMUser vu = new VMUser() { Address = u.Address, createtime = u.createtime, createuser = u.createuser, email = u.email, DeptId = u.DeptId, Id = u.Id, LoginName = u.LoginName, LoginTime = u.LoginTime, Sex = u.Sex, Status = u.Status, Password = u.Password, roles = u.roles, Phone = u.Phone, updatetime = u.updatetime, updateuser = u.updateuser, UserName = u.UserName };
                    if (!string.IsNullOrEmpty(u.roles))
                    {
                        foreach (string str in u.roles.Split(","))
                        {
                            if (roles.ContainsKey(str.ToInt()))
                            {
                                vu.rolename += roles[str.ToInt()].Name + ",";
                            }
                        }
                    }
                    //vu.allroleid = data;
                    list.Add(vu);
                }
                result.Data = list;
            }
            catch (Exception ex)
            {
                result.ResultCode = 1;
                result.ResultMsg = ex.Message;
                _logger.LogError(ex.Message);
            }
            return result;
        }

        public ResultType AddUser(user m)
        {
            ResultType result = new ResultType();
            var tran = db.Database.BeginTransaction();
            try
            {
                m.Password = MD5Utils.GetMD5_32(MD5Utils.GetMD5_32("123456"));
                m=db.users.Add(m).Entity;
                db.SaveChanges();
                List<userrole> urs = new List<userrole>();
                foreach(var str in m.roles.Split(','))
                {
                    userrole ur = new userrole() {RoleId=str.ToInt(),UserId=m.Id };
                    urs.Add(ur);
                }
                db.userrole.AddRange(urs);
                db.SaveChanges();
                tran.Commit();
            }
            catch (Exception ex)
            {
                result.ResultCode = 1;
                result.ResultMsg = ex.Message;
                tran.Rollback();
                _logger.LogError(ex.Message);
            }
            return result;
        }
        
        public ResultType UpdateUser(user item )
        {
            ResultType result = new ResultType();
            var tran = db.Database.BeginTransaction();
            try
            {
                db.users.Update(item);
                db.Entry(item).Property(p => p.Password).IsModified = false;
                db.Entry(item).Property(p => p.createtime).IsModified = false;
                db.Entry(item).Property(p => p.createuser).IsModified = false;
                db.SaveChanges();

                db.userrole.RemoveRange(db.userrole.FromSqlRaw(string.Format("select * from userrole where userid={0}",item.Id)));
                db.SaveChanges();

                List<userrole> urs = new List<userrole>();
                foreach(var str in item.roles.Split(","))
                {
                    userrole ur = new userrole() { RoleId=str.ToInt(),UserId=item.Id};
                    urs.Add(ur);
                }
                db.userrole.AddRange(urs);
                db.SaveChanges();
                tran.Commit();
            }
            catch (Exception ex)
            {
                result.ResultCode = 1;
                result.ResultMsg = ex.Message;
                _logger.LogError(ex.Message);
                tran.Rollback();
            }
            return result;
        }
        public ResultType<VMUser> GetUserByUserId(int id)
        {
            ResultType<VMUser> result = new ResultType<VMUser>();
            try
            {
                user u = db.users.Find(id);
                var data = db.roles;
                var roles = data.ToList().ToDictionary(p => p.Id);

                VMUser vu = new VMUser() { Address = u.Address, createtime = u.createtime, createuser = u.createuser, email = u.email, DeptId = u.DeptId, Id = u.Id, LoginName = u.LoginName, LoginTime = u.LoginTime, Sex = u.Sex, Status = u.Status, Password = u.Password, roles = u.roles, Phone = u.Phone, updatetime = u.updatetime, updateuser = u.updateuser, UserName = u.UserName };
                foreach (string str in u.roles.Split(","))
                {
                    if (roles.ContainsKey(str.ToInt()))
                    {
                        vu.rolename += roles[str.ToInt()].Name + ",";
                    }
                }
                vu.allroleid = data;
                result.Data= vu;
            }
            catch (Exception ex)
            {
                result.ResultCode = 1;
                result.ResultMsg = ex.Message;
                _logger.LogError(ex.Message);
            }
            return result;
        }
        public ResultType DeleteUser(List<user> m)
        {
            ResultType result = new ResultType();
            try
            {
                db.users.RemoveRange(m);
                db.SaveChanges();
            }
            catch (Exception ex)
            {
                result.ResultCode = 1;
                result.ResultMsg = ex.Message;
                _logger.LogError(ex.Message);
            }
            return result;
        }

        #endregion

        #region 角色

        public ResultType<List<role>> GetAllRole()
        {
            ResultType<List<role>> result = new ResultType<List<role>>();
            try
            {
                result.Data = db.roles.ToList();
            }
            catch (Exception ex)
            {
                result.ResultCode = 1;
                result.ResultMsg = ex.Message;
                _logger.LogError(ex.Message);
            }
            return result;
        }

        public ResultType AddRole(VMRole r)
        {
            ResultType result = new ResultType();
            var tran = db.Database.BeginTransaction();
            try
            {
                string menuList = r.MenuId;
                role rr = r;
                rr = db.roles.Add(rr).Entity;
                db.SaveChanges();
                List<rolemenu> lrm = new List<rolemenu>();
                if (!string.IsNullOrEmpty(menuList))
                {
                    foreach (string str in menuList.Split(','))
                    {
                        rolemenu rm = new rolemenu();
                        rm.roleid = rr.Id;
                        rm.menuid = str.ToInt();
                        lrm.Add(rm);
                    }
                    db.rolemenu.AddRange(lrm);
                    db.SaveChanges();
                }
                tran.Commit();
            }
            catch (Exception ex)
            {
                result.ResultCode = 1;
                result.ResultMsg = ex.Message;
                tran.Rollback();
            }
            finally
            {
                tran.Dispose();
            }
            return result;
        }
        public ResultType<List<TreeListModel>> GetAllMenuRole()
        {
            ResultType<List<TreeListModel>> result = new ResultType<List<TreeListModel>>();
            List<menu> data = db.menus.ToList();
            List<TreeListModel> treeModels = new List<TreeListModel>();
            foreach (menu m in data)
            {
                TreeListModel menu = new TreeListModel() { id = m.id, title = m.title, parentid = m.parentid };
                treeModels.Add(menu);
            }
            Dictionary<int, TreeListModel> dict = treeModels.ToDictionary(loc => loc.id);
            foreach (TreeListModel loc in dict.Values)
            {
                if (0 == (loc.parentid))
                {
                    continue;
                }

                if (loc.parentid != loc.id)
                {
                    dict[loc.parentid.Value].children.Add(loc);
                }
            }
            foreach (TreeListModel loc in dict.Values)
            {
                if (0 != loc.parentid)
                {
                    dict.Remove(loc.id);
                }
            }
            result.Data = dict.Values.ToList();
            return result;
        }
        public ResultType<Dictionary<string, object>> GetRoleByRoleId(int id)
        {
            ResultType<Dictionary<string, object>> result = new ResultType<Dictionary<string, object>>();
            List<menu> data = db.menus.ToList();
            string sql = string.Format(@"SELECT
	                            m.*
                            FROM
	                            menu m
                            LEFT JOIN rolemenu rm ON m.id = rm.menuid
                            WHERE
	                            rm.roleid = {0}", id);
            List<int> data1 = db.menus.FromSqlRaw(sql).ToList().Select(p => p.id).ToList();
            result.Data.Add("role", db.roles.Find(id));
            List<TreeListModel> treeModels = new List<TreeListModel>();
            foreach (menu m in data)
            {
                TreeListModel menu = new TreeListModel() { id = m.id, title = m.title, parentid = m.parentid };
                if (data1.Contains(m.id))
                {
                    menu.@checked = true;
                }
                else
                {
                    menu.@checked = false;
                }
                treeModels.Add(menu);
            }
            Dictionary<int, TreeListModel> dict = treeModels.ToDictionary(loc => loc.id);
            foreach (TreeListModel loc in dict.Values)
            {
                if (0 == (loc.parentid))
                {
                    continue;
                }

                if (loc.parentid != loc.id)
                {
                    dict[loc.parentid.Value].children.Add(loc);
                    if (dict[loc.parentid.Value].children.Count != 0)
                    {
                        dict[loc.parentid.Value].@checked = false;
                    }
                }
            }
            foreach (TreeListModel loc in dict.Values)
            {
                if (0 != loc.parentid)
                {
                    dict.Remove(loc.id);
                }
            }
            result.Data.Add("Menu", dict.Values.ToList());
            return result;
        }
        public ResultType UpdateRole(VMRole r)
        {
            ResultType result = new ResultType();
            var tran = db.Database.BeginTransaction();
            try
            {
                string menuList = r.MenuId;
                role rr = r;
                db.rolemenu.RemoveRange(db.rolemenu.FromSqlRaw(string.Format("select * from rolemenu where roleid={0}", rr.Id)));
                db.SaveChanges();
                List<rolemenu> lrm = new List<rolemenu>();
                if (!string.IsNullOrEmpty(menuList))
                {
                    foreach (string str in menuList.Split(','))
                    {
                        rolemenu rm = new rolemenu();
                        rm.roleid = rr.Id;
                        rm.menuid = str.ToInt();
                        lrm.Add(rm);
                    }
                    db.rolemenu.AddRange(lrm);
                    db.SaveChanges();
                }
                db.roles.Update(rr);
                db.Entry(rr).Property(p => p.createtime).IsModified = false;
                db.Entry(rr).Property(p => p.createuser).IsModified = false;
                db.SaveChanges();
                tran.Commit();
            }
            catch (Exception ex)
            {
                result.ResultCode = 1;
                result.ResultMsg = ex.Message;
                tran.Rollback();
            }
            finally
            {
                tran.Dispose();
            }
            return result;
        }

        public ResultType DeleteRole(List<role>  m)
        {
            ResultType result = new ResultType();
            try
            {
                db.roles.RemoveRange(m);
                db.SaveChanges();
            }
            catch (Exception ex)
            {
                result.ResultCode = 1;
                result.ResultMsg = ex.Message;
                _logger.LogError(ex.Message);
            }
            return result;
        }

        public void Logout(string userId)
        {
            redisService.DeleteByKeyAsync(userId);
            redisService.DeleteByKeyAsync(userId + "_role");
        }




        #endregion
    }
}
